#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <pthread.h>
#include <unistd.h>
using namespace std;


pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int tickets = 10000;
// 使用条件变量修改抢票代码
void *GetTicket(void* args) {
    string threadname = static_cast<const char*>(args);
    // 加锁
    while (true) {
        // 单纯的互斥，能保证数据的安全，但不一定合理或高效
        pthread_mutex_lock(&mutex);
        if (tickets > 0) {
            cout << "thread : " << threadname << " get a ticket: " << tickets-- << endl;
            usleep(1000);
            
        } else {
            cout << "thread : " << threadname << ", no ticket " << endl; // 背后有大量的线程疯狂的在申请锁和释放锁，浪费锁资源
            // 没有票了，就应该到特定的条件变量下去等待
            pthread_cond_wait(&cond, &mutex); 
            // 1、pthread_cond_wait让线程在等待的过程中，会自动释放锁，所以要传入一把锁
            // 2、线程被唤醒的时候，是在临界区中被唤醒的，当线程被唤醒是时，线程在pthread_cond_wait返回的时候，
            // 需要重新申请并持有锁，只有在持有锁的条件下，线程才能够醒来
            // 3、当线程醒来是，重新申请并持有锁，本质也要参与说的竞争
        }
        // 解锁
        pthread_mutex_unlock(&mutex);
    }
    
}
int main() {
    // 创建线程
    pthread_t t1,t2, t3;
    pthread_create(&t1, nullptr, GetTicket, (void*)"thread-1");
    pthread_create(&t2, nullptr, GetTicket, (void*)"thread-2");
    pthread_create(&t3, nullptr, GetTicket, (void*)"thread-3");
    while (true) {
        if (tickets == 0) {
            pthread_mutex_lock(&mutex);
            tickets += 1000;
            // 唤醒线程
            sleep(5);
            pthread_mutex_unlock(&mutex);
            // pthread_cond_broadcast(&cond);// 唤醒所有线程 
            pthread_cond_signal(&cond);
        }
        // sleep(1);
        // 唤醒进程
        // pthread_cond_signal(&cond);
    }
    pthread_join(t1, nullptr);
    pthread_join(t2, nullptr);
    pthread_join(t3, nullptr);
    return 0;
}










// // 条件变量接口的基本使用

// // 创建一个条件变量
// pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// // 再创建一把锁
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// void *func(void* args) {
//     string threadname = static_cast<const char*>(args);
//     while (true) {
//         // sleep(1);
//         // 加锁
//         pthread_mutex_lock(&mutex);
//         // 访问临界资源时，想让所有线程在指定的条件变量下等待
//         pthread_cond_wait(&cond, &mutex);
//         cout << "I am a nwethread: " << threadname << endl;
//         // 解锁
//         pthread_mutex_unlock(&mutex);
//     }

// }

// // 条件变量的基本用法
// int main() {
//     pthread_t t1, t2, t3;
//     // 创建线程
//     pthread_create(&t1, nullptr, func, (void*)"thread-1");
//     pthread_create(&t2, nullptr, func, (void*)"thread-2");
//     pthread_create(&t3, nullptr, func, (void*)"thread-3");

//     // 需要让主线程唤醒其他线程
//     while (true) {
//         sleep(1);
//         // pthread_cond_signal(&cond); // 只唤醒一个线程
//         pthread_cond_broadcast(&cond); // 唤醒所有线程
//     }
//     pthread_join(t1, nullptr);
//     pthread_join(t2, nullptr);
//     pthread_join(t3, nullptr);
//     return 0;
// }